///////////////////////////////////////////////////////////////////////////////
//
// Licensed under the MIT License
//
// Copyright (c) 2010 Chris Colinsky
// All Rights Reserved
//
// version	0.5
// http://code.google.com/p/sugarcookie/
// http://code.google.com/p/sugarcookie/wiki/License
//
////////////////////////////////////////////////////////////////////////////////

package sugarcookie.preloaders {
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.utils.getDefinitionByName;
	
	import sugarcookie.events.GenericEvent;
	
	/**
	 * Provides functionality to preload an ActionScript Project by taking advntage of some Flex functionality to create a 2 frame SWF file.  The first frame is used to display a prelaoder graphic and monitor the load.  All code and asseted not associated with the class is pushed to frame 2 of the SWF so it can be preloaded.
	 */
	public class AppLoader extends MovieClip {
		//--------------------------------------------------------------------------
	    //
	    //  Class constants
	    //
	    //--------------------------------------------------------------------------
		
		/**
		 * Defines the value of the <code>type</code> property of an <code>onApplicationReady</code> event object.
		 * 
		 * <p>The properties of the event object have the following values:</p>
	     * <table class="innertable">
	     * <tr><th>Property</th><th>Value</th></tr>
	     * <tr><td><code>bubbles</code></td><td>true</td></tr>
	     * <tr><td><code>cancelable</code></td><td>false</td></tr>
	     * <tr><td><code>status</code></td><td>true</td></tr>
	     * <tr><td><code>isLoggable</code></td><td>true</td></tr>
	     * <tr><td><code>data</code></td><td>optional object to send data with event.</td></tr>
	     * </table>
	     *
	     * @eventType adapterResultEvent
	     * @see sugarcookie.events.GenericEvent
		 */
		public static const APPLICATION_READY:String = "onApplicationReady";
		
		public static const PROGRESS_COMPLETE:String = "progressComplete";
		
		//--------------------------------------------------------------------------
	    //
	    //  Class properties
	    //
	    //--------------------------------------------------------------------------
		
		/**
		 * This is defined in the subclass constructor and has to be the name of the root class for the ActionScript project.
		 */
		protected var _classDef:String;
		
		/**
		 * Displays the preloading graphics.
		 */
		protected var _display:IPreloader;
		
		private var _app:Object;
		
		//--------------------------------------------------------------------------
	    //
	    //  Constructor
	    //
	    //--------------------------------------------------------------------------
		
		/**
		 * Class constructor.
		 */
		public function AppLoader() {
			stop();
			
			addEventListener(Event.ADDED_TO_STAGE,onAdded);
			addEventListener(APPLICATION_READY,onApplicationReady);
		}
		
		//--------------------------------------------------------------------------
	    //
	    //  Class methods
	    //
	    //--------------------------------------------------------------------------
		
		/**
		 * Can be overridden in subclass, but be sure to take note of the Template pattern so to not interrupt the flow of the application.  Monitors the loading of the applciation and provides progress information.
		 * 
		 * @param evt Event object dispatched by Flash for the Event.ENTER_FRAME event.
		 */
		protected function onEnterFrame(evt:Event):void {
			if (framesLoaded == totalFrames) {
				removeEventListener(Event.ENTER_FRAME, onEnterFrame);
				progressDisplay(1);
				nextFrame();
				startup();
			} else {
				var perc:Number = root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal;
				progressDisplay(perc);
			}
		}
		
		/**
		 * This method should be overriden to instantiate preloader display objects and add then to the display list.
		 */
		protected function init():void {
			//override to set-up loader graphics
		}
		
		/**
		 * Called during onEnterFrame event handler to provide loading percentage information.
		 * 
		 * @aram perc Percentage of preload.
		 */
		protected function progressDisplay(perc:Number):void {
			_display.setPercent(perc);
		}
		
		/**
		 * Once the AppLoader subclass object has been added to the display list. This method is overridden to animate in the preloader.
		 */
		protected function showLoader():void {
			_display.onShow();
		}
		
		/**
		 * Called when the AppLoader.APPLICATION_READY event is received.  This method is overridden to animate out the preloader.
		 */
		protected function hideLoader():void {
			_display.onHide();
		}
		
		/**
		 * AppLoader.APPLICATION_READY event handler.  This event is dispatched when the application is ready to display itself and requires that the preloader be removed from the screen.
		 */
		protected function onApplicationReady(evt:GenericEvent):void {
			hideLoader();
		}
		
		/**
		 * Override to manage resize events.
		 */
		protected function onResize(evt:Event=null):void {
			
		}
		
		protected function initDisplay():void {
			if (stage.hasEventListener(Event.RESIZE)) {
				stage.removeEventListener(Event.RESIZE,onResize);
				x=y=0;
			}
			_app.initDisplay();
		}
		
		protected function destroyChildren(evt:Event):void {
			_display.removeEventListener(PROGRESS_COMPLETE,destroyChildren);
			removeChild(DisplayObject(_display));
			_display = null;
			initDisplay();
		}
		
		// private members
		/**
		 * Initiates the AppLoader to begin monitoring the preloading process.
		 * @private
		 */
		private function onAdded(evt:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE,onAdded);
			
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			
			stage.addEventListener(Event.RESIZE,onResize);
			onResize();
			
			init();
			
			if (_display!=null) {
				_display.addEventListener(PROGRESS_COMPLETE,destroyChildren);
				addChild(DisplayObject(_display));
			} else {
				throw new Error("No progress display defined, _display is null.");
			}
			
			showLoader();
			
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		
		/**
		 * Starts up the application after preloading has completed.
		 * @private
		 */
		private function startup():void {
			_display.progressComplete();
			
			var mainClass:Class = Class(getDefinitionByName(_classDef));
			if(mainClass) {
				_app = new mainClass();
				addChildAt(_app as DisplayObject,0);
				_app.startup();
			}
		}
	}
}